import toQueryString from '../utils/toQueryString';
import processHeader from './processHeader';
import CustomResponse from './customResponse';
import { CustomError, CustomErrorType } from '../customError';
import { reportError } from '../actions/error';

// avoid warning when developer dosn't handle api customError.
window.addEventListener('unhandledrejection', (e) => {
  e.preventDefault();
});

/**
 * 用于创建fetch请求
 * @class Request
 * @memberOf fe-lib.FetchRequest
 * @inner
 */
export default class CustomRequest {
  static instance = new CustomRequest();
  static dispatch = null;

  /**
   * @constructor
   */
  constructor() {
    ['get', 'post', 'put', 'patch', 'delete', 'head'].forEach((method) => {
      this[method] = (path, { ajaxCache = true, headers = {}, credentials = 'include', mode = 'cors', body = undefined } = {}) => {
        let url = path;
        const fetchConfig = {
          method,
          headers: processHeader(headers),
          credentials,
          mode
        };

        let params = body;
        if (fetchConfig.headers['Content-Type'] !== 'application/json') {
          params = toQueryString(body);
        }

        if (method !== 'get' && method !== 'delete') {
          fetchConfig.body = params;
        } else {
          const paramList = [];
          if (params) {
            paramList.push(params);
          }
          if (ajaxCache) {
            paramList.push(`_timestamp=${Date.now()}`);
          }
          if (paramList.length > 0) {
            url = `${url}?${paramList.join('&')}`;
          }
        }

        return fetch(url, fetchConfig)
          .then((res = {}) => {
            const ret = CustomRequest.preHandleResponse(res);
            if (ret) {
              throw ret;
            }

            const { status, statusText = '', ok } = res;
            if (ok) {
              return res.json();
            }

            throw new CustomError(statusText, CustomErrorType.HTTP, {
              code: status,
              url
            });
          })
          .then((json) => {
            const response = new CustomResponse(json);
            if (response.success) {
              return {
                ...response
              };
            }

            throw new CustomError(response.message, CustomErrorType.SERVICE, {
              code: response.code,
              url
            });
          }).catch((error) => {
            if (CustomRequest.dispatch) {
              CustomRequest.dispatch(reportError(error));
            } else {
              console.warn(JSON.stringify(error));
            }
            throw error;
          });
      };
    });
  }

  /**
   * 绑定store到Request
   * @function connectToRedux
   * @param store - redux store
   * @memberOf Request
   * @static
   */
  static connectToRedux(store) {
    CustomRequest.dispatch = store.dispatch;
  }

  /**
   * 预处理fetch请求响应头
   */
  static preHandleResponse() {
    return false;
  }

  static resetStatic(methods) {
    Object.keys(methods).forEach(key => (CustomRequest[key] = methods[key]));
  }
}
